/**
 * 数据代理，将数据代理到对象中，并使用路径访问深层次数据
 * @author zj
 * @date 2024/08/22
 */

/**
 * 设置数据代理
 * @param values
 */
export const getValuesProxy = (values: object | object[]): any => {
  return new Proxy(values, {
    get(target: object, key: string | symbol, receiver: any): any {
      // if (key !== '__v_isShallow' && key !== '__v_isReadonly' && key !== '__v_raw') {
      if (typeof key === 'string' && key.indexOf('__') !== 0) {
        if (key in target) {
          return Reflect.get(target, key);
        } else {
          return getValueByPath(target, key);
        }
      }
      return target;
    },
    set(target: object, key: string | symbol, value: any) {
      if (typeof key === 'string' && key.indexOf('__') !== 0) {
        if (key in target) {
          Reflect.set(target, key, value);
        } else {
          setValueByPath(target, key, value);
        }
      }
      return true;
    }
  });
};

/**
 * 设置默认值
 * @param columns
 * @param valuesProxy
 */
export const setValuesProxy = (valuesProxy: object, columns: { keyName?: string, defaultValue?: any, datatype?: string }[]) => {
  columns.forEach((column) => {
    if (column.keyName) {
      const keyName = column.keyName;
      const defaultValue = column.defaultValue;
      const _value = valuesProxy[keyName];
      valuesProxy[keyName] = _value || defaultValue;
    }
  });
};

/**
 * 清空值
 * @param columns
 * @param valuesProxy
 */
export const clearValuesProxy = (columns: { keyName?: string, datatype?: string }[], valuesProxy: object) => {
  columns.forEach((column) => {
    if (column.keyName) {
      const keyName = column.keyName;
      const val = valuesProxy[keyName];
      if (val === undefined || val === null) {
        return;
      }
      // valueProxy[prop] = undefined;
      if (typeof val === 'string') {
        valuesProxy[keyName] = null;
      } else if (Object.prototype.toString.call(val) === '[object Array]') {
        valuesProxy[keyName] = [];
      } else if (typeof val === 'object') {
        valuesProxy[keyName] = {};
      } else {
        valuesProxy[keyName] = null;
      }
    }
  });
};

/**
 * 通过路径设置值
 * @param data
 * @param paths
 * @param value
 */
export const setValueByPath = (data: any, paths: string, value?: any): void => {
  if (paths) {
    const attrNames = splitPaths(paths);
    if (attrNames.length > 0) {
      let parentValue = data;
      let lastIndex = attrNames.length - 1;
      for (let i = 0; i < attrNames.length; i++) {
        const attrName = removeUnnecessary(attrNames[i]);
        if (!attrName) {
          return;
        }
        if (lastIndex === i) {
          Reflect.set(parentValue, attrName, value);
        } else {
          const nextAttrName = removeUnnecessary(attrNames[i + 1]);
          if (!nextAttrName) {
            return;
          }
          const nextArrayIndex = getArrayIndex(nextAttrName);
          // row.yx[1][2][3].xz.name
          const thisIsArray = nextArrayIndex !== undefined;
          const nextParentValue = Reflect.get(parentValue, attrName);
          const arrayIndex = getArrayIndex(attrName);
          if (attrName === 'rr') {
            // debugger
          }
          if (thisIsArray) {
            // next level is array
            if (nextParentValue === undefined || nextParentValue === null ||
              Object.prototype.toString.call(nextParentValue) !== '[object Array]') {

              if (Object.prototype.toString.call(parentValue) === '[object Array]') {
                if (arrayIndex !== undefined) {
                  for (let j = 0; j < arrayIndex + 1; j++) {
                    parentValue.push([]);
                  }
                  parentValue = Reflect.get(parentValue, attrName);
                }
              } else if (typeof parentValue === 'object') {
                Reflect.set(parentValue, attrName, []);
                parentValue = Reflect.get(parentValue, attrName);
              }

            } else {
              parentValue = nextParentValue;
            }
          } else {
            // next level is object
            if (nextParentValue === undefined || nextParentValue === null ||
              Object.prototype.toString.call(nextParentValue) === '[object Array]' ||
              typeof nextParentValue !== 'object') {

              if (Object.prototype.toString.call(parentValue) === '[object Array]') {
                if (arrayIndex !== undefined) {
                  for (let j = 0; j < arrayIndex + 1; j++) {
                    parentValue.push({});
                  }
                  parentValue = Reflect.get(parentValue, attrName);
                }
              } else if (typeof parentValue === 'object') {
                Reflect.set(parentValue, attrName, {});
                parentValue = Reflect.get(parentValue, attrName);
              }

            } else {
              parentValue = nextParentValue;
            }
          }
        }
      }
    }
  }
  return data;
};

/**
 * 通过路径获取值
 * @param data
 * @param paths
 */
export const getValueByPath = (data: any, paths: string): any => {
  if (data) {
    let tempValue = data;
    const attrNames = splitPaths(paths);
    if (attrNames.length > 0) {
      const lastIndex = attrNames.length - 1;
      for (let i = 0; i < attrNames.length; i++) {
        if (tempValue && typeof tempValue === 'object') {
          const attrName = removeUnnecessary(attrNames[i]);
          if (!attrName) {
            return;
          }
          if (lastIndex === i) {
            return Reflect.get(tempValue, attrName);
          } else {
            tempValue = Reflect.get(tempValue, attrName);
            if (!tempValue) {
              return;
            }
            continue;
          }
        }
        return;
      }
    }
  }
};

/**
 * 获取数组索引
 * @param attrName
 */
export const getArrayIndex = (attrName: string): number | undefined => {
  const arrayIndex = parseInt(attrName);
  if (!isNaN(arrayIndex)) {
    return arrayIndex;
  }
};

/**
 * 分割路径
 * @param paths
 * test.name.age[1].name[sex].1.3[name].sex.8p..[name.sex].age...[.name.sex]
 */
export const splitPaths = (paths: string): string[] => {
  // const attrNames = paths.split('.');
  // noinspection RegExpRedundantEscape
  try {
    // return paths.match(/(^[^(.)^\[]+)|(\[\d+\])|(\[[\s\S]+?\])|((?<=\.)[^(.)^\[]+)/g) || [];
    // return paths.match(/(^[^(.)^\[]+)|(\[\d+\])|(\[[\s\S]+?\])|([^(.)^\[]+)/g) || [];
    return paths.match(/(^[^(.)^\[]+)|(\[\d+])|(\[[\s\S]+?])|([^(.)^\[]+)/g) || [];
  } catch (e) {
    return [];
  }
};

/**
 * 移除路径上不必要的[]元素
 * @param path
 */
export const removeUnnecessary = (path: string): string | undefined => {
  if (path) {
    // noinspection RegExpSingleCharAlternation,RegExpRedundantEscape
    return path.replace(/\[|]/g, '');
  }
};

